import React, {useState} from 'react';
import DrawerEnhance from "common/drawer/DrawerEnhance";
import {App, Button, Flex, Form, Popconfirm, Space, Table, Typography} from "antd";
import {ConsumeItem} from "type/ConsumeItem";
import {requestDelete, requestGet, requestPost, requestPut} from "util/request";
import LogFactory from "log/LogFactory";
import {uuid32} from "util/uuid";
import {compareObjectMergeProps, compareObjectToDifference} from "util/compare";
import {Rule} from "rc-field-form/lib/interface";
import {PlusOutlined} from "@ant-design/icons";
import {consumeItemColumnsBase} from "columns/ConsumeItemColumns";
import {inputMap, inputTypeMap} from "maps/init";
import {EditableCellProps} from "type/EditableCellProps";

const log = LogFactory.getLog("ConsumeItemComponent") ;

/**
 * 可编辑单元格组件,如果表格处于编辑状态,则显示输入框,否则显示数据
 */
const EditableCell: React.FC<EditableCellProps<ConsumeItem>> = ({editing, dataindex, title, inputtype, record, index, children, ...restProps}) => {
    if (editing){
        let rules: Rule[] = dataindex === "item" ? [{required: true, message: `请输入${title},此字段必须填写!`,}] : [] ;
        return (
            <td {...restProps}>
                <Form.Item name={dataindex} style={{ margin: 0 }} rules={ rules } >
                    {inputMap.get(inputtype)}
                </Form.Item>
            </td>
        );
    }
    return <td {...restProps}>{children}</td> ;
};

const ConsumeItemComponent = () => {
    const [form] = Form.useForm<ConsumeItem>();
    const { message } = App.useApp() ;
    const [data, setData] = useState<Partial<ConsumeItem>[]>([]) ;
    /**
     * 当前选择编辑数据行的key
     */
    const [editingKey, setEditingKey] = useState<string>();
    /**
     * 当前添加数据行的key
     */
    const [addKey, setAddKey] = useState<string>();
    /**
     * 判断当前行是否处于编辑状态
     */
    const isEditing = (record: ConsumeItem): boolean => record.key === editingKey;
    /**
     * 编辑表格时,保存数据的回调
     * @param key 当前编辑行的key
     */
    const save = async (key: React.Key) => {
        let rowData: ConsumeItem | null = null ;
        try {
            rowData = (await form.validateFields()) as ConsumeItem;
        }catch (e){
            log.error("表单验证失败: " , e) ;
            return ;
        }
        // 如果是添加key为空,表示当前是编辑状态,更新数据
        if (addKey === void 0){
            await updateHandler(rowData) ;
            setEditingKey(void 0) ;
            return ;
        }
        await addHandler(rowData) ;
        setAddKey(void 0) ;
        setEditingKey(void 0) ;
    } ;
    /**
     * 更新数据处理函数
     * @param values 需要更新的数据
     */
    const updateHandler = async (values: ConsumeItem) => {
        log.debug("更新数据: " , values) ;
        const index = data.findIndex((item) => editingKey === item.key);
        const origin = data[index] ;
        log.debug("更新数据原始值: " , origin) ;
        let compRes = compareObjectToDifference(origin,values) ;
        log.debug("数据对比结果: " , compRes) ;
        if (compRes === null){
            message.info("数据没有变化,无需更新!") ;
            return ;
        }
        compRes.id = origin.id ;
        const res = await requestPost<ConsumeItem>("/record/consume-item",compRes).then(res=>res) ;
        log.request("从服务器更新数据结果",res) ;
        if (res.success){
            message.success("更新数据成功!") ;
            let newData = compareObjectMergeProps(origin,values) ;
            // [从索引位置开始截取] 索引位置的数据 [从索引位置+1向后截取]
            setData([...data.slice(0, index), newData, ...data.slice(index + 1)]);
        }else {
            message.warning("更新数据失败!") ;
        }
    } ;
    const addHandler = async (values: ConsumeItem) => {
        log.debug("添加数据: " , values) ;
        // 这个添加就应该把新的数据反回来
        const res = await requestPut<ConsumeItem>("/record/consume-item",values).then(res=>res) ;
        log.request("从服务器添加数据结果",res) ;
        if (res.success){
            message.success("添加数据成功!") ;
            const newData = [...data] ;
            const index = newData.findIndex((item) => editingKey === item.key);
            newData.splice(index,1);
            newData.unshift(res.data) ;
            setData(newData);
        }else {
            message.warning("添加数据失败!") ;
        }
    } ;
    /**
     * 取消编辑的回调
     * @param key 当前编辑行的key
     */
    const cancel = (key?: React.Key) => {
        // 当前点击取消时,判断当前行是新增行还是编辑行,如果是编辑行,则将编辑行的key设置为空,如果是新增行,则删除新增行
        if(addKey === void 0){
            // 如果新增行的key为空,表示现在是编辑状态
            log.debug("取消编辑行: " , editingKey) ;
            setEditingKey(void 0) ;
            return ;
        }
        if (editingKey && addKey){
            log.debug("删除新增行: " , addKey) ;
            // 如果添加编辑key都有值表示当前是新增状态
            setEditingKey(void 0) ;
            setAddKey(void 0) ;
            setData(data.filter(item => item.key !== key)) ;
        }
    } ;
    /**
     * 编辑表格数据的回调
     * @param record 当前编辑行的数据
     */
    const edit = (record: Partial<ConsumeItem>) => {
        log.debug("编辑数据: " , record) ;
        // 当点击编辑时,将当前行的数据设置到表单中,添加时候设置空数据到表单中
        form.setFieldsValue({item: undefined,order: 0 ,explain: undefined ,show: true,remark: undefined,...record});
        setEditingKey(record.key);

    };
    /**
     * 删除表格数据的回调
     * @param record 当前删除行的数据
     */
    const onDelete = async (record: ConsumeItem) => {
        log.debug("删除数据: " , record) ;
        let res = await requestDelete<number>("/record/consume-item/" + record.id).then(res=>res) ;
        if (res.success){
            message.success("删除数据成功!") ;
            setData(data.filter(item => item.key !== record.key)) ;
        }else {
            message.warning("删除数据失败!") ;
        }
    } ;
    /**
     * 添加表格数据的回调
     */
    const addItemClick = async () => {
        let addUuid = uuid32() ;
        log.debug("添加数据新的报销单项目: " , addUuid) ;
        setAddKey(addUuid) ;
        setEditingKey(addUuid) ;
        setData([{key: addUuid},...data]) ;
        form.setFieldsValue({item: "",order: 0 ,explain: "" ,show: true,remark: ""});
    } ;
    const afterOpenChange = async () => {
        const res = await requestGet<ConsumeItem[]>("/record/consume-item/list").then(res=>res) ;
        if (res.success){
            setData(res.data) ;
        }
    } ;
    const consumeItemColumns = [
        ...consumeItemColumnsBase ,
        {
            title: '操作',
            key: 'operation' ,
            align: "center",
            width: 100,
            editable: false ,
            dataIndex: 'operation',
            render: (_:any, record: ConsumeItem) => {
                if (isEditing(record)){
                    // 当前行处于编辑状态,显示保存和取消按钮
                    return (
                        <span>
                            <Typography.Link onClick={() => save(record.key)} style={{ marginRight: 8 }}>保存</Typography.Link>
                             <Button style={{padding: 0}} type={"link"} onClick={() => cancel(record.key)}>取消</Button>
                        </span>
                    );
                }else {
                    // 当前行不处于编辑状态,显示编辑按钮和删除按钮
                    return (
                        <Space>
                            <Typography.Link disabled={editingKey !== void 0} onClick={() => edit(record)}>
                                编辑
                            </Typography.Link>
                            <Popconfirm title={"是否要确认删除?"} onConfirm={async () => await onDelete(record) }>
                                <Button disabled={editingKey !== void 0} style={{padding: 0}} type={"link"}>删除</Button>
                            </Popconfirm>
                        </Space>
                    );
                }
            },
        }
    ] ;
    /**
     * 表格渲染列的选项
     */
    const mergedOptionColumns = consumeItemColumns.map((col) => {
        if (!col.editable) {
            return col;
        }
        return {
            ...col,
            onCell: (record: ConsumeItem) => ({
                record,
                inputtype: inputTypeMap.get(col.dataIndex), // 设置表格为编辑状态的时候,输入框的类型使用map根据数据的key来设置
                dataindex: col.dataIndex,
                title: col.title,
                align: col.align ,
                editing: isEditing(record),
            }),
        };
    });
    return (
        <DrawerEnhance title={"编辑报销选项"} size={"large"} afterOpenChange={afterOpenChange}>
           <Flex style={{ margin: "10px 1px" }}>
               <Button onClick={addItemClick} type={"primary"} icon={<PlusOutlined />}>添加项目</Button>
           </Flex>
            <Form form={form} component={false}>
                <Table<Partial<ConsumeItem>>
                    loading={false}
                    components={{
                        body: {
                            cell: EditableCell,
                        },
                    }}
                    bordered
                    size={"small"}
                    dataSource={data}
                    columns={mergedOptionColumns as any}
                    rowClassName="editable-row"
                />
            </Form>

        </DrawerEnhance>
    );
};

export default ConsumeItemComponent;